#ifndef PARTIDA_H_
#define PARTIDA_H_

#include "defines.h"
#include "elemento/Elemento.h"
#include "elemento/Barril.h"
#include "elemento/Donkey.h"
#include "elemento/Fuego.h"
#include "elemento/Mario.h"
#include "elemento/Martillo.h"
#include "ParametrosDificultad.h"
#include "SharedMemory.h"
#include "Semaforo.h"
//Comandos
#include "comando/ComandoServidor.h"
#include "comando/ComandoMover.h"
#include "comando/ComandoCrearFuego.h"
#include "comando/ComandoCrearBarril.h"
#include "comando/ComandoCrearMartillo.h"
#include "comando/ComandoDeleteFuego.h"
#include "comando/ComandoDeleteBarril.h"
#include "comando/ComandoDeleteMartillo.h"
#include "comando/ComandoLanzarBarril.h"
#include "comando/ComandoFinTramo.h"
#include "comando/ComandoFinNivel.h"
#include "comando/ComandoFinPartida.h"
#include "comando/ComandoSalirJuego.h"
#include "map"

using namespace std;

/*
 * Clase que modela la partida en si, contiene toda la logica para interpretar y ejecutar acciones y responder a los jugadores.
 */
class Partida {
private:
	//Instancia del juego.
    static Partida *instance;

    //Jugadores
    t_partida partida;

    //Indicador de actividad.
	bool activo;
	bool stoped;
	bool finTorneo;

	/* Punteros a la memoria compartida y al semaforo para sincronizar su uso */
    SharedMemory *shm;
	Semaforo	 *semShm;

	//Lista de elementos en la partida.
	list<Elemento *> listaElementos;

	//Colas de salidas a los jugadores 1 y 2 para que procesen los cambios.
	queue<t_accion> colaRespuestaAcciones;

	//Cola de t_acciones a ejecutar.
	queue<t_accion> 	colaAcciones;

	//Mutex para recursos criticos.
	ThreadMutex	*mutexListaElementos;			//Para uso exclusivo de la cola
	ThreadMutex	*mutexColaAcciones;				//Para uso exclusivo de la cola
	ThreadMutex	*mutexColaRespuestaAcciones;	//Para uso exclusivo de la cola
	ThreadMutex	*mutexHayRespuestas;			//Para saber si hay respuestas a enviar.
	ThreadMutex	*mutexHayAcciones;  			//Para saber si hay t_acciones a procesar.

	//nivel actual de la partida
	 short int nivelActual;
	 short int tramoActual;

	//Contadores para saber cuantos elementos de cada uno tengo id para los que son unicos y indicador de sentid de desplazamiento para ralph
	short int cantBarriles;
	short int cantCiclosSinFuegos;
	short int cantCiclosSinTortas;
	short int idDonkey;
	short int idFuego;
	short int idMartillo;
	short int sentidoRalph;
	int cantVidriosRotos;

	//Parametrizaciones
	int maxMovSinLanzar;		//Cantidad de movimientos de ralph antes de lanzar, según nivel.
	int maxCiclosSinFuegos;		//Loops esperar entre aparicion de cada fuego, según nivel.
	int maxCiclosSinTortas;		//Loops esperar entre aparicion de cada torta, según nivel.
	int cantBloqueosAQuitarH;	//Define la cantidad de bloqueos horizontales a quitar, define dificultad del nivel
	int cantBloqueosAQuitarV;	//Define la cantidad de bloqueos verticales a quitar, define dificultad del nivel
	int cantTramosNivelActual;	//Cantidad de tramos que tiene el nivel actual.


    //------------------------------------notificaciones a los jugadores-------------------------------------------//

	//Notifica a los jugadores que comienza la partida, que numero de jugador son y cual es el nombre del otro jugador
	bool notificarInicioPartida(Socket *conexion);
	/* Envia a los jugadores la accion de finalizar partida */
	void notificarFinPartida();
	/* Notifica a los jugadores los cambios obtenidos del servidor torneo, puede optar por puntaje, o ranking o ambos. */
	void notificarActEstadoJugadores(bool puntaje, bool ranking);
	/* Notifica a los jugadores que se actualizo el ranking de los jugadores */
	void notificarActRankingJugadores();
	/* Notifica a los jugadores que se actualizo el puntaje de los jugadores */
	void notificarActPuntajeJugadores();
	/* Notifica a los jugadores si ya se termino el tramo y o el nivel, con las acciones correspondientes */
	void notificarFinTramoONivel();
	/* Notifica a los jugadores que comienza un nuevo tramo enviando el numero de tramo y la semilla para el sorteo de vidrios y bloqueos */
	void notificarInicioTramo( short int tramo, int semilla);
	/* Notifica a los jugadores que comienza la partida y pueden accionar */
	void notificarComenzar( short int tramo);

	//----------------------------Resets, para cuando se inicializa el tramo--------------------------------------//
	/* Resetea todos los elementos que son persistentes dentro de la partida o nivel y no se crean en el tramo */
	void resetObjetosPorTramo();
	/* Inicializa ralph a la posicion inicial del tramo y su cantidad de movimientos sin lanzar */
	void resetDonkey();
	/* Inicializa los felix1 y felix2 a la posicion inicial y los desinmuniza */
	void resetMarios();
	/* Elimina las feugos existentes en el tramo */
	void resetFuego();
	/* Elimina la torta existente en el tramo */
	void resetMartillo();
	/* Elimina los ladrillos existentes en el tramo */
	void resetBarriles();

	/* Setea la dificultad del nivel */
	void setParmsPorNivel( short int nivel);

    //------------------------------------------acciones Automaticas----------------------------------------------//

	//Crea a ralph, ventanas rotas y los felix.
	void crearElementosIniciales();
	//Animacion de Fuego.
	void eventoAnimarFuego();
	//Animacion de torta.
	void eventoAnimarTorta();
	//Animacion de ladrillos.
	void eventoAnimarLadrillos();
	//Animacion de ralph.
	void eventoAnimarRalph();
	//Animacion de Donkeys
	void eventoAnimarDonkey();

	//encola una accion que crea un feugo.
	void crearAccionFuego();
	//encola una accion que crea una torta.
	void crearAccionTorta();
	//encola una accion para que ralph lance un ladrillo hacia abajo.
	void crearAccionLanzarBarril(Donkey *donkey);
	/* Encola como accion a procesar el fin de tramo o nivel si es el ultimo tramo del nivel. */
	void crearAccionFinTramoONivel();

    //------------------------------------------Utilidades internas----------------------------------------------//
	/* Encola la accion a ejecutar propia de terminar la partida */
	void terminarPartida();
	/* Chequea que si se dio el fin de partida o no */
	bool esFinDePartida();
	//accion que crea a felix.
	void crearMario(int nroMario);
	//accion que crea a donkey.
	void crearDonkey();
	//Crea el stock inicial de tortas pero no vivas(una)
	void crearMartilloInicial();
	//Crea el stock inicial de fuegos pero no vivas (una)
	void crearFuegoInicial();
	//Crea el stock inicial de ladrillos 5, pero no vivos.
	void crearBarrilesIniciales();

	/* Metodo que se fija si ya no quedan vidrios rotos y finaliza el tramo, si es el ultimo tramo del nivel finaliza el nivel. */
	void verFinTramoONivel();
	/* Verifica si el elemento recien movido, no colisiono contra algo, si es asi devuelve contra que. */
	Elemento *hayColision(Elemento *enMovimiento);
	/* Cuando se detecto una colision, este metodo genera las acciones pertinentes dependiendo del los tipos de entidad colisionados.*/
	void procesarColision(Elemento *colisionador, Elemento *colisionado);
	/* Una vez que se verifico que colisiono un felix y que este no era inmune */
	void colisionar(Mario *mario, Elemento *elemento);
	/* Hace que felix consuma la torta, se vuelva inmune y desaparezca la torta de la pantalla. */
	void consumirMartillo(Mario *mario, Martillo *martillo);
	/* Revive un ladrilo y lo posiciona en los x,y ingresados por parametro. */
	void reutilizarBarril(Barril *barril, int posX, int posY);


	/* 													Herramientas en general 												*/
	/* Trae el puntero al elemento del id ingresado, de la lista de elementos de la partida */
	Elemento *getElementoById(int id);

	/* 									Herramientas para gestion de la memoria compartida 										*/
	/* Trae el puntero a la estructura partida que esta en memoria compartida. */
	t_partida getPartidaCompartida();
	/* Actualiza los datos de la partida almacenada en shm con el servidor torneo. */
	void actualizarMemoriaCompartida(t_partida *partida);

	/* Actualiza el puntaje del felix enviado por parametro sobre el jugador correspondiente dentro de la partida y en memoria compartida */
	void actualizarJugadorServidorTorneo(Mario *jugador);

	/* Actualiza los datos locales de los jugadores con lo existente en la shm con el torneo */
	bool actualizarEstadoJugadores();

public:
    //Límites de la pantalla.
	static const int limiteSuperior 		= LIM_SUP;
	static const int limiteInferior 		= LIM_INF;
	static const int limiteIzquierdo		= LIM_IZQ;
	static const int limiteDerecho 			= LIM_DER;

	//----------------------------------------------Basicos----------------------------------------------------//
	//GetInstance del patrón singleton
    static Partida* getInstance();
    //Constructor por defecto.
	Partida();
    //Destructor.
    ~Partida();
    //Ver si sigue activa la partida
    bool isActivo();

    //Getters
    t_partida *getPartida();
    t_jugador *getJugadorXNro( short int);
    bool isStoped();

    //Setters 
    void setStoped(bool stoped);
    void setShm(SharedMemory *shm);
    void setSemShm(Semaforo *semShm);
    void setPartida(t_partida *partida);

    /* Metodo que inicializa la partida, y envia a los jugadores que numero de jugador son y el nombre de su contrincante */
    bool iniciarPartida(Socket *conexion);
    /* Método que inicializa un nivel con el número de nivel */
    void inicializarNivel( short int nivel);
    /* Método que inicializa el tramo, sorteando los bloqueos y vidrios rotos del mismo. */
    void inicializarTramo(unsigned int tramo);

    /* Metodo que accede a la memoria compartida para actualizar el ranking de los jugadores de la partida que actualiza el serverTorneo */
    void refreshStatsJugadores(bool puntaje, bool ranking);


	//-------------------------------------------Utilitarios--------------------------------------------------//

	//Agrega la t_accion recibida por parámetro, a la cola de t_acciones a ejecutar.
	void encolarAccionAProcesar(t_accion action);
	//Va sacando de la cola de t_acciones, para ejecutarlas.
	t_accion desencolarAccionAProcesar();
	//Procesa el siguiente evento en la cola de t_acciones a procesar.
	void procesarAccion();
	//Agrega la t_accion recibida por parámetro, a la cola de respuestas a los jugadores.
	t_accion desencolarRespuestaJugadores();
	//Va sacando de la cola de respuestas, para enviar a los jugadores.
	void encolarRespuestaJugadores(t_accion action);
	//Realiza los movimientos de los objetos animados del juego.
	void animar();
	/* Busca los parametros que definen la dificultad del nivel indicado y los setea en las variables parametros */
    void setParmsPorNivel( short int nivel, int *maxMovSinLanzar, int *MaxCiclosSinFuegos, int *cantBloqueosAQuitarH, int *cantBloqueosAQuitarV, int *maxCiclosSinTortas, int *cantTramosNivelActual);

	/* Actualiza los datos de la partida en la memoria compartida para el servidor de torneo. */
	void actualizarJugadorServidorTorneo();
	void setFinTorneo(bool finTorneo);
	bool isFinTorneo();
    //---------------------------------------acciones Solicitadas-----------------------------------------------//
    //Metodo para realizar la t_accion de mover ingresada por parametro, primero valida.
	int move(t_accion *action);
	/* Activa un objeto fuego y le asigna el x y solicitado en la accion recibida. */
	bool crearFuego(t_accion *action);
	/* Activa una torta  y le asigna el vidrio solicitado en la accion recibida. */
	bool crearMartillo(t_accion *action);
	/* Activa un ladrillo del stock de ladrillos libres en la posicion donde lo indica la accion */
	bool crearLadrillo(t_accion *action);
	/* Metodo para eliminar un fuego */
	bool deleteFuego(t_accion *action);
	/* Metodo para eliminar un ladrillo */
	bool deleteBarril(t_accion *action);
	/* Metodo para eliminar un torta */
	bool deleteMartillo(t_accion *action);
	/* Ejecuta la accion de lanzado de un ladrillo para ralph. */
	bool lanzarLadrillo(t_accion *action);
	/* Ejecuta la accion de quitar a un jugador del juego y de la partida */
	bool salirDelJuego(t_accion *action);
	//Pasa al siguiente tramo.
	bool finalizarTramo(t_accion *action);
	//Pasa al siguiente nivel.
	bool finalizarNivel(t_accion *action);
	//Termina la partida.
	bool finalizarPartida(t_accion *action);

	//---------------------------------------------------------------------------------------------------//

    //Metodo que realiza el movimiento en si.
	void mover(t_accion *action);
	//Metodo de desaparicion de objetos
	int desaparecer(t_accion *action);
	//Verifica si no existen marquesinas o ventanas abiertas para felix.
	bool sePuedeMover(t_accion *action);
	/* Ve si existe un bloqueo entre los vidrios elegidos */
	bool existeBloqueo(short int vidrioOrigen, short int vidrioDestino);
};

#endif /* PARTIDA_H_ */
